import javax.media.j3d.*;
import javax.vecmath.AxisAngle4f;
import javax.vecmath.Vector3f;

import java.awt.Component;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.*;

public abstract class HeadBehavior extends Behavior {

	protected TransformGroup viewPlatform;
    protected Transform3D transform_ = new Transform3D ();
    protected WakeupOr wakeupCriteria;
    
}


/**
 * Class controls head movement using a tracker.
 */
class TrackerHeadBehavior extends HeadBehavior {

    private Sensor sensor = null;
    private Transform3D transform_ = new Transform3D();

    
    public TrackerHeadBehavior(TransformGroup viewPlatform, Sensor sensor) {
    	this.viewPlatform = viewPlatform;
		this.sensor = sensor;
		wakeupCriteria = new WakeupOr(new WakeupCriterion[]{new WakeupOnElapsedFrames(0)});
    }
    
    public void initialize() {
    	wakeupOn(wakeupCriteria);
    }

    public void processStimulus (Enumeration criteria) {
    	
    	/* tracker control */
    	sensor.getRead(transform_);
    	viewPlatform.setTransform(transform_);

    	/*Next wake up condition*/
    	wakeupOn(wakeupCriteria);
    }
    
}

/**
 * Class controls head movement via a keyboard listener
 */
class KeyboardHeadBehavior extends HeadBehavior implements KeyListener {

	private Transform3D viewTransform = new Transform3D(); 	/** transform used during rotation */

	private final Vector3f up = new Vector3f(0f, 1f, 0f); 	/** vector point up, used for rotation */
	
	private long lastTick = System.currentTimeMillis(); 	/** last system time in milliseconds since an update */
	
	private boolean button[] = {false, false}; /** state of rotate left and rotate right button respectively */
	
	private final static float ROTATION_SPEED = 
		Float.parseFloat(VR.getDefaults().getProperty("KEYBOARD_ROTATION_SPEED"));	/** speed at which the user rotates (in radians per second) */
	
	private static int[] KEY_ROTATE_LEFT  = VR.getKeyCodeForKeyboardControl("rotate_left");

	private static int[] KEY_ROTATE_RIGHT = VR.getKeyCodeForKeyboardControl("rotate_right");
	
	
    public KeyboardHeadBehavior(Component c, TransformGroup viewPlatform){
    	this.viewPlatform = viewPlatform;
    	c.addKeyListener(this);
    	wakeupCriteria = new WakeupOr(new WakeupCriterion[]{new WakeupOnElapsedFrames(0)});
    }

    public void initialize() {
    	wakeupOn(wakeupCriteria);
    }

    public void processStimulus (Enumeration criteria) {

    	float diff = (System.currentTimeMillis() - lastTick) / 1000.0f;
    	
    	/* keyboard control */
		if (button[0])
			rotateAboutVertical(ROTATION_SPEED * diff);
		if (button[1])
			rotateAboutVertical(-ROTATION_SPEED * diff);

		lastTick = System.currentTimeMillis();
		
    	/*Next wake up condition*/
    	wakeupOn(wakeupCriteria);
    }
    
    /** rotate the user view around the Y-axis (left or right) */
    protected void rotateAboutVertical(float radians) {

		viewTransform = new Transform3D();
		viewPlatform.getTransform(viewTransform);
	
		up.set(0f, 1f, 0f);
		viewTransform.transform(up);
		AxisAngle4f rotation = new AxisAngle4f (up.x, up.y, up.z, radians);
		Transform3D rotationTform = new Transform3D();
		rotationTform.setRotation(rotation);
	
		viewTransform.mul(rotationTform);
		viewPlatform.setTransform(viewTransform);
    }

	public void keyPressed(KeyEvent e) {
		int c = e.getKeyCode();
		if (VR.contains(KEY_ROTATE_LEFT, c))
			button[0] = true;
		else if (VR.contains(KEY_ROTATE_RIGHT, c))
			button[1] = true;
	}

	public void keyReleased(KeyEvent e) {
		int c = e.getKeyCode();
		if (VR.contains(KEY_ROTATE_LEFT, c))
			button[0] = false;
		else if (VR.contains(KEY_ROTATE_RIGHT, c))
			button[1] = false;
	}

	public void keyTyped(KeyEvent e) { }
}
